package com.gitee.wsl.struct.grammar.ext

import com.gitee.wsl.struct.grammar.GrammarContext
import com.gitee.wsl.struct.grammar.parser.Parser
import com.gitee.wsl.struct.grammar.parser.combinator.optional
import com.gitee.wsl.struct.grammar.parser.combinator.repeated
import com.gitee.wsl.struct.grammar.parser.parser


/**
 * Creates a new parser that tries to apply the given [parser]
 * and fallbacks to returning null in case of failure.
 *
 * ```kotlin
 * object : Grammar<Tuple2<String?, String>> {
 *    val title by regexToken("Mrs?\\.?")
 *    val ws by regexToken("\\s+")
 *    val surname by regexToken("\\w+")
 *    override val root by maybe(title) * -maybe(ws) * surname
 */
fun <T : Any> GrammarContext.maybe(parser: Parser<T>): Parser<T?> = optional(parser)

/**
 * Creates a new parser that tries to apply the given [parser]
 * and fallbacks to returning null in case of failure.
 *
 * ```kotlin
 * object : Grammar<Tuple2<String?, String>> {
 *    val title by regexToken("Mrs?\\.?\\s+")
 *    val surname by regexToken("\\w+")
 *    override val root by optional(title) * surname
 */
fun <T : Any> GrammarContext.optional(parserBlock: Parser<T>): Parser<T?> = parserBlock.optional()

fun <T : Any> GrammarContext.repeated(p: Parser<T>, atLeast: Int, atMost: Int = -1): Parser<List<T>> =  p.repeated(atLeast, atMost)

fun <T : Any> GrammarContext.zeroOrMore(p: Parser<T>) = repeated(p, atLeast = 0)

fun <T : Any> GrammarContext.oneOrMore(p: Parser<T>) = repeated(p, atLeast = 1)

/**
 * Creates a new parser that applies the given [parser], but ignores the result and returns `Unit`.
 *
 * ```kotlin
 * object : Grammar<String> {
 *     val title by regexToken("Mrs?\\.?\\s+")
 *     val surname by regexToken("\\w+")
 *     override val root by ignored(title) and surname
 * }
 * ```
 */
fun GrammarContext.ignored(parser: Parser<*>): Parser<Unit> = ignored(parser)